from uuid import UUID

from django.db import models
from django.core.exceptions import ValidationError


class OptimizedUUIDField(models.Field):
    """
    跨数据库兼容的 UUID 字段：
    - MySQL: BINARY(16)
    - PostgreSQL: UUID
    - SQLite: BLOB
    - Oracle: RAW(16)
    """

    def __init__(self, *args, **kwargs):
        kwargs['max_length'] = 16  # 对 MySQL/Oracle 逻辑有用
        super().__init__(*args, **kwargs)

    def deconstruct(self):
        name, path, args, kwargs = super().deconstruct()
        del kwargs['max_length']
        return name, path, args, kwargs

    def db_type(self, connection):
        """
        根据数据库返回列类型
        """
        vendor = connection.vendor
        if vendor == 'mysql':
            return 'binary(16)'
        elif vendor == 'postgresql':
            return 'uuid'
        elif vendor == 'oracle':
            return 'RAW(16)'
        elif vendor == 'sqlite':
            return 'blob'
        else:
            raise NotImplementedError(f"Unsupported database vendor: {vendor}")

    # --- Python <-> DB 转换 ---

    def from_db_value(self, value, expression, connection):
        """
        从数据库读取时，将 bytes会uuid 转为 uuid.UUID 对象
        """
        if value is None:
            return value

        if isinstance(value, UUID):
            return value

        if isinstance(value, bytes):
            if len(value) == 16:
                return UUID(bytes=value)
            else:
                raise ValidationError(f"Invalid byte length for UUID: {len(value)}")

        if isinstance(value, str):
            # Oracle 可能返回 hex 字符串？一般不会，但兼容
            try:
                return UUID(hex=value.replace('-', ''))
            except ValueError:
                raise ValidationError(f"Invalid UUID string: {value}")

        raise ValidationError(f"Unsupported value type: {type(value)}")

    def to_python(self, value):
        if isinstance(value, UUID) or value is None:
            return value
        if isinstance(value, bytes):
            return UUID(bytes=value)
        if isinstance(value, str):
            return UUID(value)

        raise ValidationError(f"Cannot convert {type(value)} to UUID")

    def get_db_prep_value(self, value, connection, prepared=False):
        """
        写入数据库前，将 uuid.UUID 转为 bytes或uuid str
        """
        if value is None:
            return None

        if not isinstance(value, UUID):
            if isinstance(value, bytes):
                value = UUID(bytes=value)
            else:
                value = UUID(str(value))

        vendor = connection.vendor
        if vendor == 'postgresql':
            return str(value)  # Django 会将其作为 UUID 处理
        else:
            return value.bytes  # MySQL, Oracle, SQLite 都接受 bytes

    def value_to_string(self, obj):
        value = self.value_from_object(obj)
        return str(value) if value is not None else ''

    def formfield(self, **kwargs):
        from django.forms import UUIDField
        defaults = {'form_class': UUIDField}
        defaults.update(kwargs)
        return super().formfield(**defaults)
